package com.fotoloka.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import com.fotoloka.services.Factory;
import com.fotoloka.services.FotoService;
import com.fotoloka.services.impl.OpenCVWebCam;
import com.fotoloka.util.MensagensUtil;
import com.fotoloka.util.ParamUtil;

public class Janela extends JFrame implements KeyListener {

	private static final int INTERVALO_INICIO_SECAO = 4500;
	
	private static final int INTERVALO_CONTAGEM_REGRESSIVA = 1300;
	
	private static final int INTERVALO_ULTIMA_CONTAGEM_REGRESSIVA = 1000;

	private static final int TAMANHO_POR_CARACTER_PEQUENO = 40;

	private static final int TAMANHO_POR_CARACTER_MEDIO = 60;

	private static final int TAMANHO_POR_CARACTER_GRANDE = 100;
	
	private Color cinza = new Color(53, 141, 151);
	
	private Color vermelho = new Color(142, 26, 4);
	
	private Color azulEscuro = new Color(20,1,44);

	private static final Font FONT_GRANDE = new Font("Arial", Font.BOLD,
			TAMANHO_POR_CARACTER_GRANDE);

	private static final Font FONT_MEDIA = new Font("Broadway", Font.BOLD,
			TAMANHO_POR_CARACTER_MEDIO);

	private static final Font FONT_PEQUENA = new Font("Vladimir Script",
			Font.BOLD, TAMANHO_POR_CARACTER_PEQUENO);

	public static final int FOTOS_POR_VEZ = 4;

	private static final int TAMANHO_CONTAGEM_REGRESSIVA = 5; // 5

	private static final long serialVersionUID = 1L;

	private OpenCVWebCam webCam;

	private Botao baterFoto;

	private Botao baterFotoSemImpressao;

	private Rotulo rotulo;

	private FotoService fotoService;

	private int width;

	private int height;
	
	private boolean emOperacao = false;

	public Janela(int width, int height) {
		super();
		fotoService = Factory.buildFotoService();
		this.width = width;
		this.height = height;
		addKeyListener(this);
	}

	public void loadWebCam() throws Exception {

		int numeroDispositivo = ParamUtil.getNumeroWebCam();
		int width = 800;//ParamUtil.getResolucao().width;
		int height = 448;//ParamUtil.getResolucao().width;
		webCam = new OpenCVWebCam(numeroDispositivo, width, height
				
				);

		baterFoto = new Botao(this.webCam,
				"*********      INICIAR       ******", true);
		baterFoto.setPreferredSize(new Dimension(400, 22));
		baterFoto.setBounds(100, 100, 80, 22);
		baterFoto.setVisible(true);
		baterFoto.setVisible(true);
		webCam.add(baterFoto);

		baterFotoSemImpressao = new Botao(this.webCam,
				"*********      INICIAR      ******", true, 100);
		baterFotoSemImpressao.setPreferredSize(new Dimension(250, 22));
		baterFotoSemImpressao.setBounds(100, 100, 80, 22);
		baterFotoSemImpressao.setVisible(false);
		//webCam.add(baterFotoSemImpressao);

		rotulo = new Rotulo(webCam, TAMANHO_CONTAGEM_REGRESSIVA + "");
		rotulo.setForeground(cinza);
		rotulo.setPreferredSize(new Dimension(60, 300));
		rotulo.setFont(FONT_GRANDE);
		rotulo.setVisible(false);
		webCam.add(rotulo);		
		
		baterFotoSemImpressao.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Thread runner = new Thread() {
					public void run() {
						prepararAndFotografar();
					}

				};
				runner.start();
			}
		});

		baterFoto.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Thread runner = new Thread() {
					public void run() {
						prepararAndFotografar();
					}

				};
				runner.start();
			}
		});

		getContentPane().add(webCam, BorderLayout.CENTER);
		webCam.start();

		getContentPane().validate();
		getContentPane().repaint();
		
		testarParametros();
	}
	
	public void testarParametros() {
		ParamUtil.getDiretorioPadrao();
		ParamUtil.getImpressora();
		ParamUtil.getResolucao();
		ParamUtil.isImprimir();
		ParamUtil.getMonitor();
	}

	public void prepararAndFotografar() {
		emOperacao = true;
		int tamContagem = TAMANHO_CONTAGEM_REGRESSIVA;
		baterFoto.setVisible(false);
		baterFotoSemImpressao.setVisible(false);
		rotulo.setVisible(true);
		
		rotulo.setFont(FONT_MEDIA);
		rotulo.setForeground(cinza);
		String mensagemDeNovo = "INICIANDO FOTO-X";
		int largura = mensagemDeNovo.length()
				* (TAMANHO_POR_CARACTER_MEDIO - 15);
		rotulo.setPreferredSize(new Dimension(largura, 300));
		rotulo.setText(mensagemDeNovo);
		
		pause(INTERVALO_INICIO_SECAO);
		
		for (int j = 0; j < FOTOS_POR_VEZ; j++) {
			for (int i = tamContagem; i > 0; i--) {
				try {
					rotulo.setFont(FONT_GRANDE);
					rotulo.setForeground(cinza);
					webCam.setPause(false);
					rotulo.setPreferredSize(new Dimension(60, 300));
					rotulo.setText("" + i);
					Thread.yield();
					if(i == 1) {
						Thread.sleep(INTERVALO_ULTIMA_CONTAGEM_REGRESSIVA);
					} else {
						Thread.sleep(INTERVALO_CONTAGEM_REGRESSIVA);
					}
				} catch (InterruptedException ite) {
					ite.printStackTrace();
				}
			}

			webCam.setPause(true);

			armazenarFoto();
			
			mensagemBateFoto();

			mensagemDeNovo(j);

			// tamContagem = getNovoTamanhoContagem(tamContagem);
		}

		try {
			rotulo.setForeground(vermelho);
			String text = "Muito obrigado pela presença.";

			largura = text.length() * TAMANHO_POR_CARACTER_PEQUENO + 100;
			rotulo.setPreferredSize(new Dimension(largura - 800, 400));
			rotulo.setFont(FONT_PEQUENA);
			rotulo.setText(text);

			// criar
			//int secao = fotoService.getUltimaSecao();
			//fotoService.gerarFotoImpressao();
			
			if (ParamUtil.isImprimir()) {
				Logger.getLogger(Janela.class.toString()).log(Level.INFO, "Seção finalizada. Iniciando impressão do cartão fotografia.");
				try {
					fotoService.gerarFotoImpressao();
					Image ultimaFotoSecao = fotoService.getUltimaFotoSecao();
					pause(300);
					webCam.setImage(ultimaFotoSecao);
					rotulo.setVisible(false);
					fotoService.imprimir();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
			Thread.yield();
			pause(8000);
		} finally {
			// TODO adicionar efeito
		
			rotulo.setText("AGUARDANDO INÍCIO DA SESSÃO");
			rotulo.setVisible(false);
			baterFoto.setVisible(true);
			baterFotoSemImpressao.setVisible(true);
			webCam.setPause(false);
			emOperacao = false;
		}

	}

	public int getNovoTamanhoContagem(int tamContagem) {
		if (tamContagem == TAMANHO_CONTAGEM_REGRESSIVA) {
			tamContagem--;
		}
		return tamContagem;
	}

	public void mensagemDeNovo(int j) {
		if (j < FOTOS_POR_VEZ - 1) {
			try {
				rotulo.setFont(FONT_MEDIA);
				rotulo.setForeground(cinza);
				String mensagemDeNovo = MensagensUtil.getMensagemDeNovo();
				int largura = mensagemDeNovo.length()
						* (TAMANHO_POR_CARACTER_MEDIO - 15);
				rotulo.setPreferredSize(new Dimension(largura, 300));
				rotulo.setText(mensagemDeNovo);
				Thread.yield();
				Thread.sleep(3000);
			} catch (InterruptedException ite) {
				ite.printStackTrace();
			}
		}
	}

	public void armazenarFoto() {
		try {
			fotoService.armazenar(webCam.getImgImpressao());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void mensagemBateFoto() {
		try {
			rotulo.setFont(FONT_MEDIA);
			rotulo.setForeground(vermelho);
			String mensagemBateFoto = MensagensUtil.getMensagemBateFoto();
			int largura = mensagemBateFoto.length()
					* (TAMANHO_POR_CARACTER_MEDIO - 15);
			rotulo.setPreferredSize(new Dimension(largura, 300));
			rotulo.setText(mensagemBateFoto);
			Thread.yield();
			Thread.sleep(1500);
		} catch (InterruptedException ite) {
			ite.printStackTrace();
		}
	}

	@Override
	public void dispose() {
		super.dispose();
		if (webCam != null) {
			webCam.stop();
		}
		System.exit(0);
	}

	public void windowClosed(WindowEvent e) {
		JOptionPane.showMessageDialog(this, "Fechou Corretamente.", "Info"
				+ "rmação", JOptionPane.INFORMATION_MESSAGE);
	}

	public static void main(String[] args) {
		Dimension dimension = new Dimension(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);

		GraphicsEnvironment ge = GraphicsEnvironment
				.getLocalGraphicsEnvironment();
		GraphicsDevice gd = ge.getDefaultScreenDevice();

		Janela fotoPainel = new Janela(dimension.width, dimension.height);
		fotoPainel.setUndecorated(true);
		fotoPainel.setSize(dimension);
		fotoPainel.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		fotoPainel.setVisible(true);
		fotoPainel.setAlwaysOnTop(true);
		

		try {
			fotoPainel.loadWebCam();
		} catch (Exception e) {
			e.printStackTrace();
			fotoPainel.setVisible(false);
			fotoPainel.setAlwaysOnTop(false);
			JOptionPane.showMessageDialog(null,
					"Ocorreu um erro ao tentar carregar a WebCam");
			System.exit(0);
		}

		//gd.setFullScreenWindow(fotoPainel); 
		// JOptionPane.showMessageDialog(null, "Square code detected: " + text);

	}

	
	@Override
	public void keyPressed(KeyEvent evt) {
		if(evt.getKeyCode() == KeyEvent.VK_PAGE_UP) {
		    Thread runner = new Thread() {
				public void run() {
					prepararAndFotografar();
				}
			};
			try {
				//aguarda 200 milisegundos para evitar o início de duas seções simultâneas
				Thread.sleep(200);
			} catch (InterruptedException e1) {
				//faz nada
			}	
			if(!emOperacao) {
				runner.start();
			}
		}
		
		if(evt.getKeyCode() == KeyEvent.VK_PAGE_DOWN) {
			Dimension dimension = new Dimension(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
			if(this.isAlwaysOnTop()) {
				this.setAlwaysOnTop(false);
				this.setSize((int) (dimension.width*0.95),(int) (dimension.height*0.95));
				this.setLocation((int) (dimension.width*0.025), (int) (dimension.height*0.025));
			} else {
				this.setAlwaysOnTop(true);
				this.setSize(dimension);
				this.setLocation(0,0);
			}
		}
		
		if(evt.getKeyCode() == KeyEvent.VK_ESCAPE) {
			System.exit(0);
		}
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
	}
	
	
	public void pause(int tempo) {
		try {
			Thread.sleep(tempo);
		} catch (InterruptedException e1) {
			//faz nada
		}
	}

}
